package data

import (
	_ "database/sql"
	_ "fmt"
	"gitchina/CPTT4WeChat/protobuf"
	"github.com/astaxie/beego/orm"
	_ "github.com/go-sql-driver/mysql"
)

type ApiRepo struct{}

type UserBindDto struct {
	Uid      string `orm:"column(uid)"`
	OpenId   string `orm:"column(open_id)"`
	NickName string `orm:"column(nick_name)"`
}

type GardenDto struct {
	Id        int    `orm:"pk;auto;column(id)"`
	Uid       string `orm:"column(uid)"`
	Name      string `orm:"column(name)"`
	Signature string `orm:"column(signature)"`
}

type UserDto struct {
	Id        int64  `orm:"pk;auto;column(id)"`
	GardenId  int    `orm:"column(garden_id)"`
	Uid       string `orm:"column(uid)"`
	OpenId    string `orm:"column(open_id)"`
	UserNo    string `orm:"column(user_no)"`
	Name      string `orm:"column(name)"`
	NickName  string `orm:"column(nick_name)"`
	UserType  int    `orm:"column(user_type)"`
	Signature string `orm:"column(signature)"`
	GardenUid string `orm:"-"`
}

type CheckInStatsDto struct {
	Id           int    `orm:"pk;auto;column(id)"`
	GardenId     int    `orm:"column(garden_id)"`
	OwnerId      int64  `orm:"column(owner_id)"`
	GroupId      int    `orm:"column(group_id)"`
	CategoryName string `orm:"column(category_name)"`
	CategoryType int    `orm:"column(category_type)"`
	Data         string `orm:"column(data)"`
	DataType     int    `orm:"column(data_type)"`
	DataFormat   int    `orm:"column(data_format)"`
}

type CheckInDataDto struct {
	Id          int    `orm:"pk;auto;column(id)"`
	GardenId    int    `orm:"column(garden_id)"`
	OwnerId     int64  `orm:"column(owner_id)"`
	UserNo      string `orm:"column(user_no)"`
	UserName    string `orm:"column(user_name)"`
	Data        string `orm:"column(data)"`
	DataType    int    `orm:"column(data_type)"`
	DataFormat  int    `orm:"column(data_format)"`
	LastUpdTime string `orm:"column(update_time)"`
}

func (garden *GardenDto) TableName() string {
	return "garden"
}

func (info *UserDto) TableName() string {
	return "user_bind"
}

func (c *CheckInStatsDto) TableName() string {
	return "check_in_stats"
}

func (c *CheckInDataDto) TableName() string {
	return "check_in_data"
}

func (r ApiRepo) AddGarden(dto GardenDto) (created bool, err error) {
	o := orm.NewOrm()
	created, _, err = o.ReadOrCreate(&dto, "Uid")
	return
}

func (r ApiRepo) UpdateGarden(dto GardenDto) (updated bool, err error) {
	var rowsAffected int64
	o := orm.NewOrm()
	rowsAffected, err = o.Update(&dto, "Name", "Signature")
	updated = rowsAffected >= 1
	return
}

func (r ApiRepo) GetGardenByUid(uid string) (dto GardenDto, err error) {
	o := orm.NewOrm()
	dto.Uid = uid
	err = o.Read(&dto, "Uid")
	return
}

func (r ApiRepo) GetGardenById(id int) (dto GardenDto, err error) {
	o := orm.NewOrm()
	dto.Id = id
	err = o.Read(&dto, "Id")
	return
}

func (r ApiRepo) AddUser(dto UserDto) (created bool, err error) {
	o := orm.NewOrm()
	created, _, err = o.ReadOrCreate(&dto, "Uid")
	return
}

func (r ApiRepo) UpdateUser(dto UserDto) (updated bool, err error) {
	var rowsAffected int64
	o := orm.NewOrm()
	rowsAffected, err = o.Update(&dto, "UserNo", "Name", "UserType", "Signature")
	updated = rowsAffected >= 1
	return
}

func (r ApiRepo) BindUser(dto UserDto) (bindOk bool, err error) {
	var rowsAffected int64
	o := orm.NewOrm()
	rowsAffected, err = o.Update(&dto, "OpenId", "NickName")
	bindOk = rowsAffected >= 1
	return
}

func (r ApiRepo) GetUserByUid(uid string) (dto UserDto, err error) {
	var g GardenDto
	o := orm.NewOrm()
	dto.Uid = uid
	err = o.Read(&dto, "Uid")
	if g, err = r.GetGardenById(dto.GardenId); err == nil {
		dto.GardenUid = g.Uid
	}

	return
}

func (r ApiRepo) GetUserByOpenId(openId string) (dto UserDto, err error) {
	var g GardenDto
	o := orm.NewOrm()
	dto.OpenId = openId
	err = o.Read(&dto, "OpenId")
	if g, err = r.GetGardenById(dto.GardenId); err == nil {
		dto.GardenUid = g.Uid
	}
	return
}

func (r ApiRepo) AddOrUpdateCheckInStats(stats []*protobuf.CheckInStats) (err error) {
	var list orm.ParamsList
	o := orm.NewOrm()
	for _, s := range stats {
		if _, err = o.Raw(Get_Check_In_Stats_Signature, s.Uid).ValuesFlat(&list); err == nil {
			if len(list) > 0 {
				if s.GetSignature() != list[0].(string) {
					_, err = o.Raw(Update_Check_In_Stats, s.GetData(), s.GetSignature(), s.GetUid(), list[0].(string)).Exec()
				}
			} else {
				_, err = o.Raw(Add_Check_In_Stats, s.GetUid(), s.GetGardenUid(),
					s.GetOwnerUid(), s.GetGroupId(), s.GetCategoryName(), s.GetCategoryType(),
					s.GetData(), s.GetDataType(), s.GetDataFormat(), s.GetSignature()).Exec()
			}
		}

	}
	return
}

func (r ApiRepo) GetCheckInStatsGroupByGrade(gardenId, dataType int) ([]CheckInStatsDto, error) {
	o := orm.NewOrm()
	var stats []CheckInStatsDto
	_, err := o.QueryTable("check_in_stats").
		Filter("GardenId", gardenId).
		Filter("CategoryType", 1).
		Filter("DataType", dataType).
		OrderBy("GroupId").
		All(&stats)
	return stats, err
}

func (r ApiRepo) GetCheckInStatsGroupByClass(gardenId, groupId, dataType int, ownerId int64) ([]CheckInStatsDto, error) {
	o := orm.NewOrm()
	var stats []CheckInStatsDto
	qs := o.QueryTable("check_in_stats").
		Filter("GardenId", gardenId).
		Filter("CategoryType", 2).
		Filter("DataType", dataType)
	if ownerId != 0 {
		qs = qs.Filter("OwnerId", ownerId)
	}
	if groupId != 0 {
		qs = qs.Filter("GroupId", groupId)
	}
	_, err := qs.All(&stats)
	return stats, err
}

func (r ApiRepo) AddOrUpdateCheckInData(data []*protobuf.CheckInData) (err error) {
	var list orm.ParamsList
	o := orm.NewOrm()
	for _, d := range data {
		if _, err = o.Raw(Get_Check_In_Data_Signature, d.Uid).ValuesFlat(&list); err == nil {
			if len(list) > 0 {
				if d.GetSignature() != list[0].(string) {
					_, err = o.Raw(Update_Check_In_Data, d.GetData(), d.GetSignature(), d.GetUid(), list[0].(string)).Exec()
				}
			} else {
				_, err = o.Raw(Add_Check_In_Data, d.GetUid(), d.GetGardenUid(),
					d.GetOwnerUid(), d.GetUserNo(), d.GetUserName(),
					d.GetData(), d.GetDataType(), d.GetDataFormat(), d.GetSignature()).Exec()
			}
		}
	}
	return
}

func (a ApiRepo) GetCheckInData(gardenId, dataType int, lastUpdTime string) ([]CheckInDataDto, string, error) {
	var num int64
	var err error
	var updTime string
	var checkInDataList []CheckInDataDto
	o := orm.NewOrm()
	if num, err = o.QueryTable("check_in_data").
		Filter("garden_id", gardenId).
		Filter("data_type", dataType).
		Filter("update_time__gte", lastUpdTime).
		OrderBy("id").
		All(&checkInDataList); err == nil && num > 0 {
		updTime = checkInDataList[len(checkInDataList)-1].LastUpdTime
	}

	return checkInDataList, updTime, err
}

func (a ApiRepo) GetClassInCharge(id int64) (class string, ok bool) {
	var list orm.ParamsList
	o := orm.NewOrm()
	if num, _ := o.QueryTable("check_in_stats").Filter("OwnerId", id).Limit(1).ValuesFlat(&list, "CategoryName"); num >= 0 {
		class = list[0].(string)
		ok = true
	}
	return
}

func (a ApiRepo) DailyClean() {
	o := orm.NewOrm()
	o.Raw("truncate table check_in_data").Exec()
	o.Raw("truncate table check_in_stats").Exec()
}

func init() {
	orm.RegisterModel(new(UserDto), new(GardenDto), new(CheckInStatsDto), new(CheckInDataDto))
}
